package com.yonhee.arithmetic.binarySearch;

import java.util.Arrays;
import java.util.Random;

public class BinarySearch {


    public static void main(String[] args) {
        int[] intArray = generateSortedIntArray(10, 100);

        Random random = new Random();
        int randomIndex = random.nextInt(intArray.length - 1);
        int randomInt = intArray[randomIndex];

//        int result = binarySearch(intArray, randomInt);
//        System.out.println("随机数：" + randomInt + "，在数组中的位置：" + result + "，randomIndex：" + randomIndex);

        System.out.println(8 >>> 1);
    }

    public static int binarySearch(int[] arr, int target) {
        int i = 0, j = arr.length - 1;
        while (i <= j) {
            int mid = (i + j) >>> 1; // 右移一位
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] < target) {
                i = mid + 1;
            } else if (arr[mid] > target) {
                j = mid - 1;
            }
        }
        // 未找到返回 -1
        return -1;
    }

    /**
     * 优化版二分查找
     * 优化之后的区间是左闭右开的，即 [i, j)
     */
    public static int binarySearchAdvance(int[] arr, int target) {
        int i = 0, j = arr.length;  // 注意：这里使用 j = arr.length ，而不是 j = arr.length - 1
        while (i < j) { // 注意：这里使用 < ，而不是 <=，如果使用 <=，那么当i和j相等且arr[mid] > target，那么mid也会等于j，导致死循环
            int mid = (i + j) >>> 1;
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] < target) {
                i = mid + 1;
            } else if (arr[mid] > target) {
                j = mid; // 注意：这里使用 j = mid ，而不是 j = mid - 1，这是一个左闭右开的区间
            }
        }
        return -1;
    }

    /**
     * 优化版二分查找2（左右平衡）
     * 优化之后的区间是左闭右开的，即 [i, j)
     * 1.while的循环条件变成了数组中带查找的元素个数
     * 2.当目标值大于中间值时 i = mid，而不是 mid + 1。是因为循环中else中包含了target大于等于arr[mid]的情况
     * 3.在循环外判断最终返回结果
     */
    public static int binarySearchAdvance2(int[] arr, int target) {
        int i = 0, j = arr.length;
        while (1 < j - i) {
            int mid = (i + j) >>> 1;
            if (arr[mid] > target) {
                j = mid;
            } else {
                i = mid;
            }
        }
        if (arr[i] == target) {
            return i;
        } else {
            return -1;
        }
    }

    /**
     * 二分查找leftmost 查找最左侧的目标值的索引位置
     */
    public static int binarySearchLeftMost(int[] arr, int target) {
        int i = 0, j = arr.length - 1;
        int candidate = -1;
        while (i <= j) {
            int mid = (i + j) >>> 1; // 右移一位
            if (arr[mid] == target) {
                candidate = mid;
                j = mid - 1;
            } else if (arr[mid] < target) {
                i = mid + 1;
            } else if (arr[mid] > target) {
                j = mid - 1;
            }
        }
        // 未找到返回 -1
        return candidate;
    }

    /**
     * 二分查找rightmost 查找最右侧的目标值的索引位置
     */
    public static int binarySearchRightMost(int[] arr, int target) {
        int i = 0, j = arr.length - 1;
        int candidate = -1;
        while (i <= j) {
            int mid = (i + j) >>> 1; // 右移一位
            if (arr[mid] == target) {
                candidate = mid;
                j = mid + 1;
            } else if (arr[mid] < target) {
                i = mid + 1;
            } else if (arr[mid] > target) {
                j = mid - 1;
            }
        }
        // 未找到返回 -1
        return candidate;
    }

    /**
     * 二分查找leftmost 查找最左侧的目标值的索引位置
     * 优化版
     * 返回结果为待插入的位置(比目标大的，最靠左的索引位置) ==> 大于等于目标值的最靠左的位置
     */
    public static int binarySearchLeftMostAdvance(int[] arr, int target) {
        int i = 0, j = arr.length - 1;
        while (i <= j) {
            int mid = (i + j) >>> 1; // 右移一位
            if (arr[mid] >= target) {
                j = mid - 1;
            } else {
                i = mid + 1;
            }
        }
        return i;
    }

    /**
     * 二分查找rightmost 查找最右侧的目标值的索引位置
     * 优化版
     * 返回结果为待插入的位置(比目标小的，最靠右的索引位置) ==> 小于等于目标值的最靠右的位置
     */
    public static int binarySearchRightMostAdvance(int[] arr, int target) {
        int i = 0, j = arr.length - 1;
        while (i <= j) {
            int mid = (i + j) >>> 1; // 右移一位
            if (arr[mid] <= target) {
                j = mid + 1;
            } else {
                j = mid - 1;
            }
        }
        return i - 1;
    }

    /**
     * 生成指定长度和最大随机值的递增有序整数数组并输出
     *
     * @param length   数组长度
     * @param maxValue 最大随机值（包括这个值）
     * @return 递增有序的随机整数数组
     */
    public static int[] generateSortedIntArray(int length, int maxValue) {
        int[] array = new int[length];
        Random random = new Random();
        // 生成 0 到 maxValue 的随机数
        for (int i = 0; i < length; i++) {
            array[i] = random.nextInt(maxValue + 1); // 生成 0 到 maxValue 的随机数
        }
        // 对数组进行排序
        Arrays.sort(array);

        for (int i : array) {
            System.out.print(i + " ");
        }
        System.out.println();
        return array;
    }

}
